#include "OBJProcessor.h"
#include "Logger.h"
using namespace std;

namespace Caelum {
namespace ModelData {

void OBJProcessor::skip_line(wistream &is)
{
	wchar_t next;
	is >> noskipws;
	while ((is >> next) && (next != L'\n'));
}

bool OBJProcessor::skip_comment(wistream &is)
{
	wchar_t next;
	while (is >> skipws >> next)
	{
		is.putback(next);
		if (next == L'#')
			skip_line(is);
		else
			return true;
	}
	return false;
}

bool OBJProcessor::process_line(std::wistream &is)
{
	wstring elem_id;
	wstring last_elem;
	real x, y, z;

	if (!(is >> elem_id))
		return false;
	
	if (elem_id == L"o") {
		std::wstring name;
		is >> name;

		SubObject *obj = new SubObject;
		obj->mName = name;
		mObjects.push_back(obj);
		mCurObject = obj;
	}
	if (elem_id == L"mtllib") {
		//skip for now
	}
	else if (elem_id == L"usemtl") {
		//again, skip for now
	}
	else if (elem_id == L"v") {
		is >> x >> y >> z;
		Vector3 *p = new Vector3(x, y, z);
		mCurObject->mVertPositions.push_back(p);
	}
	else if (elem_id == L"vt") {
		is >> x >> y >> z;
		is.clear(); //clear error flag if z isn't available.

		Vector3 *t = new Vector3(x, y, z);
		mCurObject->mVertPositions.push_back(t);
	}
	else if (elem_id == L"vn") {
		is >> x >> y >> z;
		if (!is.good())
		{
			x = y = z = 0;
			is.clear();
			skip_line(is);
		}

		Vector3 *n = new Vector3(x, y, z);
		mCurObject->mVertNormals.push_back(n);
	}
	else if (elem_id == L"f") {
		//TODO: Add f statement parsing.
	}

	last_elem = elem_id;
	return true;
}

OBJProcessor::OBJProcessor(wstring Path)
{
	
	wifstream f(Path.c_str(), ios::in | ios::ate);
	if (!f.is_open())
	{
		throw BaseException(L"OBJ file \"" + Path + L"\" was not found.");
	}

	const int fileSize = (int)f.tellg();
	f.seekg(0, ios::beg);

	if (fileSize == 0)
		throw BaseException(L"OBJ file \"" + Path + L"\" was empty.");

	Logger::Get() << L"Parsing OBJ file \"" << Path << L"\" (file size = " << fileSize << L" bytes)." << OS_LINE_ENDING;
	Logger::Get() << L"Note: OBJ files should not be used for anything but development and testing." << OS_LINE_ENDING;

	int percent = 10;
	while (skip_comment(f))
	{
		if ((fileSize > 1024 * 1024) && (100 * f.tellg() / fileSize >= percent)) {
			percent = 100 * (int)f.tellg() / fileSize;
			percent = (percent / 10) * 10;
			Logger::Get() << L" - "<< percent << L"% done"<< OS_LINE_ENDING;
			percent += 10;
		}

		if (!process_line(f))
			break;
	}

	f.close();
	Logger::Get() << L"Done parsing \"" << Path << L"\"." << OS_LINE_ENDING;
}


}
}